﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using Pixysoft.Tools;
using System.Threading;

namespace Pixysoft.Framework.Noebe.Core
{
    class ProxyConnection : AbstractProxyConnection, IProxyConnection
    {
        private ConnectionPool pool = null;

        private ConnectionPerformance performance = new ConnectionPerformance();

        public ProxyConnection(string connectionId, IDbConnection connection, ConnectionPool pool)
            : base(connectionId, connection)
        {
            this.pool = pool;
        }


        public void ReallyClose()
        {
            base.Close();
        }

        public void ReallyDispose()
        {
            if (this.IsDisposed())
                return;

            base.Dispose();
            this.pool = null;
            this.performance = null;
        }

        public bool TryDoRequest()
        {
            if (this.IsDisposed())
                return false;

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                this.performance.BeginRequest();

                return true;
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        public void CancelRequest()
        {
            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                this.performance.CancelRequest();
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        public void EndRequest()
        {
            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                this.performance.EndRequest();
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        public int GetStatementSize()
        {
            locker.AcquireReaderLock(Timeout.Infinite);

            try
            {
                return this.performance.GetRequestCount();
            }
            finally
            {
                locker.ReleaseReaderLock();
            }
        }

        public bool IsTimeout()
        {
            return this.performance.IsTimeout();
        }

        public ConnectionSnapshot CreateShapshot()
        {
            ConnectionSnapshot admin = new ConnectionSnapshot();
            admin.ConnectionId = this.ConnectionId;
            admin.CreateDate = this.performance.GetCreateDate();
            admin.RequestCount = this.performance.GetRequestCount();
            admin.RequestTimes = this.performance.GetRequestTimes();
            return admin;
        }

        public int GetRequestTimes()
        {
            return this.performance.GetRequestTimes();
        }

        public override void Close()
        {
            EndRequest();

            if (this.IsRemoved() && GetStatementSize() == 0)
            {
                LoggerHelper.Debug("connection is removed when close, would dispose, id = " + this.ConnectionId);

                pool.ThreadSafeRemoveRemovedConnection(this);

                this.ReallyDispose();

                this.ReallyClose();
            }
            else
            {
                //do nothing
            }
        }

        public override void Dispose()
        {
            //do nothing.
        }

        /** NON THREAD SAFE */
        class ConnectionPerformance
        {
            //increase always.
            int requestTimes = 0;

            //decrease after request
            int requestCount = 0;

            DateTime createDate = GlobalTimer.Instance.GetGlobalTime();
            DateTime currentRequestTime = DateTime.MinValue;

            public ConnectionPerformance()
            {
            }

            public void BeginRequest()
            {
                requestCount++;

                requestTimes++;

                currentRequestTime = GlobalTimer.Instance.GetGlobalTime();
            }

            public void CancelRequest()
            {
                requestCount--;

                requestTimes--;
            }

            public void EndRequest()
            {
                requestCount--;
            }

            public bool IsTimeout()
            {
                if (currentRequestTime == DateTime.MinValue)
                    return false;

                //1000 * 60 * 5
                return currentRequestTime < GlobalTimer.Instance.GetGlobalTime().AddMilliseconds(StringHelper.timeout_connection * -1);
            }

            public int GetRequestTimes()
            {
                return requestTimes;
            }

            public int GetRequestCount()
            {
                return this.requestCount;
            }

            public DateTime GetCreateDate()
            {
                return createDate;
            }

            public void Dispose()
            {

            }
        }

    }
}
